/*
 * @Author: Troubadour 2276791354@qq.com
 * @Date: 2023-11-05 00:53:02
 * @LastEditors: Troubadour 2276791354@qq.com
 * @LastEditTime: 2023-11-11 19:53:38
 * @FilePath: \MDK-ARMf:\Study\STM32F4_Project\ST7789_TFT_1_3\HARDWARE\st7796_device\st7796_device.c
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */

#include "st7796_device.h"
#include "spi.h"
// #include "fonts.h"

typedef struct
{
    uint16_t width;  // 液晶屏的宽度
    uint16_t height; // 液晶屏的高度
    uint16_t id;     // 液晶屏的ID
    uint8_t wramcmd; // ST996S写GRAM指令
    uint8_t setxcmd; // ST996S设置X坐标指令
    uint8_t setycmd; // ST996S设置Y坐标指令
    uint8_t mode;
    uint8_t xcmd;
    uint8_t ycmd;
    uint8_t calibration;
} _ST7796S_LcdSetting; // 液晶屏的一些重要参数，没注释的代表触摸屏的功能

_ST7796S_LcdSetting LcdSetting;

void ST7796S_LcdReset()
{
    ST7796_RES(0);
    HAL_Delay(100);
    ST7796_RES(1);
    HAL_Delay(50);
    ST7796_BLK(1);
}

/*写命令*/
void ST7796S_LcdWriteCommand(uint8_t command)
{
    ST7796_DC(0);
    HAL_SPI_Transmit(&hspi1, &command, 1, 5);
}

/*写数据*/
void ST7796S_LcdWriteData(uint8_t data)
{
    ST7796_DC(1);
    HAL_SPI_Transmit(&hspi1, &data, 1, 5);
}

/*向液晶屏特定寄存器写入数据*/
void ST7796S_LcdWriteReg(uint8_t registers, uint16_t data)
{
    ST7796S_LcdWriteCommand(registers);
    ST7796S_LcdWriteData(data);
}

/*设置液晶屏的扫描方向
0代表竖屏，然后依次旋转90度
*/
void ST7796S_LcdDirection(uint8_t direction)
{
    LcdSetting.setxcmd = 0x2A;
    LcdSetting.setycmd = 0x2B;
    LcdSetting.wramcmd = 0x2C;
    switch (direction)
    {
    case 0:
        LcdSetting.width = LCD_W;
        LcdSetting.height = LCD_H;
        ST7796S_LcdWriteReg(0x36, (1 << 3) | (1 << 6));
        break;
    case 1:
        LcdSetting.width = LCD_H;
        LcdSetting.height = LCD_W;
        ST7796S_LcdWriteReg(0x36, (1 << 3) | (1 << 5));
        break;
    case 2:
        LcdSetting.width = LCD_W;
        LcdSetting.height = LCD_H;
        ST7796S_LcdWriteReg(0x36, (1 << 3) | (1 << 7) | (1 << 4));
        break;
    case 3:
        LcdSetting.width = LCD_H;
        LcdSetting.height = LCD_W;
        ST7796S_LcdWriteReg(0x36, (1 << 3) | (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4));
        break;
    default:
        break;
    }
}

/*准备写入GRAM*/
void LCD_WriteRAM_Prepare(void)
{
    ST7796S_LcdWriteCommand(LcdSetting.wramcmd);
}

/*写16位数据*/
uint8_t N_Data[4] = {0};
void Lcd_WriteData_16Bit(uint16_t Data)
{
    ST7796_DC(1);
    N_Data[0] = Data >> 8;
    N_Data[1] = Data & 0x00ff;
    HAL_SPI_Transmit(&hspi1, N_Data, 2, 10);
}

/*设置显示窗口*/
void LCD_SetWindows(uint16_t xStar, uint16_t yStar, uint16_t xEnd, uint16_t yEnd)
{
    ST7796S_LcdWriteCommand(LcdSetting.setxcmd);

    ST7796S_LcdWriteData(xStar >> 8);
    ST7796S_LcdWriteData(0x00FF & xStar);
    ST7796S_LcdWriteData(xEnd >> 8);
    ST7796S_LcdWriteData(0x00FF & xEnd);
    ST7796S_LcdWriteCommand(LcdSetting.setycmd);

    ST7796S_LcdWriteData(yStar >> 8);
    ST7796S_LcdWriteData(0x00FF & yStar);
    ST7796S_LcdWriteData(yEnd >> 8);
    ST7796S_LcdWriteData(0x00FF & yEnd);

    LCD_WriteRAM_Prepare();
}

/* Lvgl 打点 */
#if __USED_LVGL_DISPLAY__

void MX_SPI1_SetTransferBit(uint32_t DataBitSize)
{
    hspi1.Instance = SPI1;
    hspi1.Init.Mode = SPI_MODE_MASTER;
    hspi1.Init.Direction = SPI_DIRECTION_1LINE;
    hspi1.Init.DataSize = DataBitSize;
    hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
    hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
    hspi1.Init.NSS = SPI_NSS_SOFT;
    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
    hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
    hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    hspi1.Init.CRCPolynomial = 10;
    if (HAL_SPI_Init(&hspi1) != HAL_OK)
    {
        Error_Handler();
    }
}

void LCD_Lvgl_DisplayFull(const lv_area_t * area, lv_color_t * color_p)
{
    LCD_SetWindows(area->x1, area->y1, area->x2, area->y2);
    ST7796_DC(1);
    MX_SPI1_SetTransferBit(SPI_DATASIZE_16BIT);
    HAL_SPI_Transmit(&hspi1, (uint8_t *)color_p, (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1), 1000);
    MX_SPI1_SetTransferBit(SPI_DATASIZE_8BIT);
    // while (Display_Count--)
    // {
    //     N_Data[0] = color_p->full >> 8;
    //     N_Data[1] = color_p->full & 0x00ff;
    //     HAL_SPI_Transmit(&hspi1, N_Data, 2, 1000);
    //     color_p++;
    // }
}

#endif

/*清屏*/
void LCD_Clear(uint16_t Color)
{
    unsigned int i, m;
    LCD_SetWindows(0, 0, LcdSetting.width - 1, LcdSetting.height - 1);
    ST7796_DC(1);
    for (i = 0; i < LcdSetting.height; i++)
    {
        for (m = 0; m < LcdSetting.width; m++)
        {
            Lcd_WriteData_16Bit(Color);
        }
    }
}

void ST7796S_LcdInit(void)
{
    ST7796S_LcdReset();
    ST7796S_LcdWriteCommand(0xF0);
    ST7796S_LcdWriteData(0xC3);
    ST7796S_LcdWriteCommand(0xF0);
    ST7796S_LcdWriteData(0x96);
    ST7796S_LcdWriteCommand(0x36);
    ST7796S_LcdWriteData(0x68);
    ST7796S_LcdWriteCommand(0x3A);
    ST7796S_LcdWriteData(0x05);
    ST7796S_LcdWriteCommand(0xB0);
    ST7796S_LcdWriteData(0x80);
    ST7796S_LcdWriteCommand(0xB6);
    ST7796S_LcdWriteData(0x00);
    ST7796S_LcdWriteData(0x02);
    ST7796S_LcdWriteCommand(0xB5);
    ST7796S_LcdWriteData(0x02);
    ST7796S_LcdWriteData(0x03);
    ST7796S_LcdWriteData(0x00);
    ST7796S_LcdWriteData(0x04);
    ST7796S_LcdWriteCommand(0xB1);
    ST7796S_LcdWriteData(0x80);
    ST7796S_LcdWriteData(0x10);
    ST7796S_LcdWriteCommand(0xB4);
    ST7796S_LcdWriteData(0x00);
    ST7796S_LcdWriteCommand(0xB7);
    ST7796S_LcdWriteData(0xC6);
    ST7796S_LcdWriteCommand(0xC5);
    ST7796S_LcdWriteData(0x24);
    ST7796S_LcdWriteCommand(0xE4);
    ST7796S_LcdWriteData(0x31);
    ST7796S_LcdWriteCommand(0xE8);
    ST7796S_LcdWriteData(0x40);
    ST7796S_LcdWriteData(0x8A);
    ST7796S_LcdWriteData(0x00);
    ST7796S_LcdWriteData(0x00);
    ST7796S_LcdWriteData(0x29);
    ST7796S_LcdWriteData(0x19);
    ST7796S_LcdWriteData(0xA5);
    ST7796S_LcdWriteData(0x33);
    ST7796S_LcdWriteCommand(0xC2);
    ST7796S_LcdWriteCommand(0xA7);

    ST7796S_LcdWriteCommand(0xE0);
    ST7796S_LcdWriteData(0xF0);
    ST7796S_LcdWriteData(0x09);
    ST7796S_LcdWriteData(0x13);
    ST7796S_LcdWriteData(0x12);
    ST7796S_LcdWriteData(0x12);
    ST7796S_LcdWriteData(0x2B);
    ST7796S_LcdWriteData(0x3C);
    ST7796S_LcdWriteData(0x44);
    ST7796S_LcdWriteData(0x4B);
    ST7796S_LcdWriteData(0x1B);
    ST7796S_LcdWriteData(0x18);
    ST7796S_LcdWriteData(0x17);
    ST7796S_LcdWriteData(0x1D);
    ST7796S_LcdWriteData(0x21);

    ST7796S_LcdWriteCommand(0XE1);
    ST7796S_LcdWriteData(0xF0);
    ST7796S_LcdWriteData(0x09);
    ST7796S_LcdWriteData(0x13);
    ST7796S_LcdWriteData(0x0C);
    ST7796S_LcdWriteData(0x0D);
    ST7796S_LcdWriteData(0x27);
    ST7796S_LcdWriteData(0x3B);
    ST7796S_LcdWriteData(0x44);
    ST7796S_LcdWriteData(0x4D);
    ST7796S_LcdWriteData(0x0B);
    ST7796S_LcdWriteData(0x17);
    ST7796S_LcdWriteData(0x17);
    ST7796S_LcdWriteData(0x1D);
    ST7796S_LcdWriteData(0x21);

    ST7796S_LcdWriteCommand(0X36);
    ST7796S_LcdWriteData(0xEC);
    ST7796S_LcdWriteCommand(0xF0);
    ST7796S_LcdWriteData(0xC3);
    ST7796S_LcdWriteCommand(0xF0);
    ST7796S_LcdWriteData(0x69);
    ST7796S_LcdWriteCommand(0X13);
    ST7796S_LcdWriteCommand(0X11);
    ST7796S_LcdWriteCommand(0X29);

    ST7796S_LcdDirection(LCD_DIRECTION);
    LCD_InvertColors(0);
    LCD_Clear(0x0000); // 清屏为黑色
}

void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
{
    LCD_SetWindows(Xpos, Ypos, Xpos, Ypos);
}

void LCD_DrawPoint(uint16_t x, uint16_t y)
{
    LCD_SetCursor(x, y); // 设置光标位置
    Lcd_WriteData_16Bit(0xFFFF);
}

void LCD_DrawPixel(uint16_t x, uint16_t y, uint16_t color)
{
    LCD_SetCursor(x, y); // 设置光标位置
    Lcd_WriteData_16Bit(color);
}

void LCD_FillRectangle(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color)
{
    // clipping
    if ((x >= LCD_W) || (y >= LCD_H))
        return;
    if ((x + w - 1) >= LCD_W)
        w = LCD_W - x;
    if ((y + h - 1) >= LCD_H)
        h = LCD_H - y;
    LCD_SetWindows(x, y, x + w - 1, y + h - 1);
    ST7796_DC(1);
    for (y = h; y > 0; y--)
    {
        for (x = w; x > 0; x--)
        {
            Lcd_WriteData_16Bit(color);
        }
    }
}

void LCD_DrawCharS(int16_t x, int16_t y, char c, int16_t textColor, int16_t bgColor, uint8_t size)
{
    uint8_t line;
    int32_t i, j;
    if ((x >= LCD_W) ||
        (y >= LCD_H) ||
        ((x + 5 * size - 1) < 0) ||
        ((y + 8 * size - 1) < 0))
        return;

    for (i = 0; i < 6; i++)
    {
        if (i == 5)
            line = 0x0;
        else
            line = Font[(c * 5) + i];
        for (j = 0; j < 8; j++)
        {
            if (line & 0x1)
            {
                if (size == 1)
                    LCD_DrawPixel(x + i, y + j, textColor);
                else
                {
                    LCD_FillRectangle(x + (i * size), y + (j * size), size, size, textColor);
                }
            }
            else if (bgColor != textColor)
            {
                if (size == 1) // default size
                    LCD_DrawPixel(x + i, y + j, bgColor);
                else
                { // big size
                    LCD_FillRectangle(x + i * size, y + j * size, size, size, bgColor);
                }
            }
            line >>= 1;
        }
    }
}

uint32_t LCD_DrawString(uint16_t x, uint16_t y, char *pt, int16_t textColor)
{
    uint32_t count = 0;
    //    if (y > 15) return 0;
    while (*pt)
    {
        LCD_DrawCharS(x * 12, y * 20, *pt, textColor, LCD_BLACK, 2);
        pt++;
        x = x + 1;
        //        if (x > 20) return count;  // number of characters printed
        count++;
    }
    return count; // number of characters printed
}

void LCD_InvertColors(int invert)
{
    ST7796S_LcdWriteCommand(invert ? LCD_INVON : LCD_INVOFF);
}

